package com.ysstech.etfmanage.service.impl;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ysstech.common.enums.YssMarketEnum;
import com.ysstech.common.exception.BusinessException;
import com.ysstech.common.service.HolidayService;
import com.ysstech.common.util.BigDecimalUtil;
import com.ysstech.common.util.DateUtil;
import com.ysstech.etfmanage.enums.EtfAccountCode;
import com.ysstech.etfmanage.entity.Account;
import com.ysstech.etfmanage.entity.AccountVo;
import com.ysstech.etfmanage.entity.ParamVo;
import com.ysstech.etfmanage.entity.Skep;
import com.ysstech.etfmanage.entity.DealDetaild;
import com.ysstech.etfmanage.enums.EtfManageEnum;
import com.ysstech.etfmanage.enums.EtfReplaceCodeEnum;
import com.ysstech.etfmanage.feign.FeignValuationService;
import com.ysstech.etfmanage.feign.entity.Quotation;
import com.ysstech.etfmanage.feign.entity.StockDealDetailed;
import com.ysstech.etfmanage.service.AccountFillService;
import com.ysstech.etfmanage.service.AccountService;
import com.ysstech.etfmanage.service.ParamService;
import com.ysstech.etfmanage.service.SkepService;
import com.ysstech.etfmanage.service.DealDetaildService;
import com.ysstech.etfmanage.thread.EtfAccountGenerateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

@Slf4j
@Service
public class ShCrossStockEtfAccountServiceImpl extends EtfAccountGenerateService<AccountVo> {
    @Autowired
    private AccountService accountService;
    @Autowired
    private AccountFillService accountFillService;
    @Autowired
    private DealDetaildService dealDetaildService;
    @Autowired
    private SkepService skepService;
    @Autowired
    private HolidayService holidayService;
    @Autowired
    private ParamService paramService;
    @Autowired
    private FeignValuationService feignValuationService;

    @Override
    public EtfAccountCode getFtype() {
        return EtfAccountCode.SH_CROSS_STOCK_ETF;
    }

    /**
     * 成份券市场
     *
     * @return
     */
    public List<String> getMarketList() {
        return Arrays.asList(YssMarketEnum.H.getCode(), YssMarketEnum.S.getCode());
    }


    /**
     * 初始化台账
     *
     * @param vo
     * @param paramVo
     * @throws Exception
     */
    public List<AccountVo> initEtfAccount(Account vo, ParamVo paramVo) throws Exception {
        Account account = new Account();
        account.setDealSeat(paramVo.getEtfSeat());
        account.setPurchaseDate(vo.getPurchaseDate());
        account.setAccountId(vo.getAccountId());
        account.setEtfType(paramVo.getEtfType());
        account.setEtfMode(paramVo.getEtfMode());
        account.setEtfMarket(paramVo.getEtfMarket());
        account.setReplaceCode(EtfReplaceCodeEnum.H_REPLACE_CODE_THREE.getCode()); //需要替代的券
        //获取深圳和上海初始化的数据
        account.setMarket(YssMarketEnum.H.getCode());
        List<Account> initListSz = accountService.queryStockInitList(account);
        account.setReplaceCode(EtfReplaceCodeEnum.H_REPLACE_CODE_ONE.getCode()); //需要替代的券
        account.setMarket(YssMarketEnum.S.getCode());
        List<Account> initListSh = accountService.queryStockCrossInitList(account);
        //深圳和上海的按照申购赎回分别按照顺序存放
        List<Account> listPurchaseData = new ArrayList<>();
        List<Account> listRedeemData = new ArrayList<>();
        initListSz.addAll(initListSh);
        String yesterday = holidayService.getNextWorkday(vo.getPurchaseDate(), -1);
        List<AccountVo> voList = new ArrayList<>();
        for (Account bean : initListSz) {
            if (null == bean) {
                continue;
            }
            //获取自己市场对应的参数信息
            ParamVo etfParamVo = paramService.getEtfParamVo(bean.getMarket(), paramVo);
            BigDecimal fzqsl = BigDecimalUtil.subtract(BigDecimalUtil.divide(
                    BigDecimalUtil.multiply(bean.getShareAmount(), bean.getOneLevelSecurityCodeAmount()), etfParamVo.getEtfBenchmarkScale(), 0)
                    , bean.getDealAmount());
            if (BigDecimalUtil.compareTo(fzqsl, BigDecimal.ZERO) <= 0) {
                continue;
            }
            bean.setAmount(fzqsl);
            bean.setPurchaseDate(vo.getPurchaseDate());
            bean.setReplaceMoney(this.handleInitReplaceMoney(bean, etfParamVo, yesterday)); //替代金额
            Quotation quotation = accountService.queryQuotation(vo.getPurchaseDate(), bean.getSecurityCode());
            if (null == quotation) {
                continue;
            }
            //今日行情
            BigDecimal unitCost = (1 == etfParamVo.getEtfOrganizationPrice()) ? quotation.getQuotationClosingPrice()
                    : quotation.getQuotationAveragePrice();
            //替代金额－数量×单位成本（当日行情）
            bean.setReplaceableMoney(BigDecimalUtil.subtract(bean.getReplaceMoney(), BigDecimalUtil.multiply(fzqsl, unitCost), 2));
            bean.setUnitCost(unitCost);
            bean.setFdate(DateUtil.strToLocalDate(vo.getPurchaseDate()));
            bean.setClearCode(EtfManageEnum.ETF_CLEAR_CODE_NO.getCode());
            bean.setAddTime(LocalDateTime.now());
            bean.setSurplusAmount(fzqsl);
            bean.setRate(BigDecimal.ONE);
            bean.setEtfType(etfParamVo.getEtfType());
            bean.setEtfMode(etfParamVo.getEtfMode());
            bean.setEtfMarket(etfParamVo.getEtfMarket());
            bean.setId(DateUtil.generateUUID());
            if (EtfManageEnum.ETF_PURCHASE.getCode().equals(bean.getBusinessType())) {
                listPurchaseData.add(bean);
            } else {
                listRedeemData.add(bean);
            }
        }
        Map<String, BigDecimal> sumReplaceMoneyMap = this.querySumReplaceMoney(vo, paramVo); //查询总的替代金额
        AccountVo etfPurchase = new AccountVo();
        etfPurchase.setList(listPurchaseData);
        etfPurchase.setSumReplaceMoney(sumReplaceMoneyMap.get(EtfManageEnum.ETF_PURCHASE.getCode()));
        voList.add(etfPurchase);
        AccountVo etfRedeem = new AccountVo();
        etfRedeem.setList(listRedeemData);
        etfRedeem.setSumReplaceMoney(sumReplaceMoneyMap.get(EtfManageEnum.ETF_REDEMPTION.getCode()));
        voList.add(etfRedeem);
        return voList;
    }

    @Override
    public List<AccountVo> renewRightEtfAccount(Account vo, ParamVo paramVo) throws Exception {
        return null;
    }

    /**
     * 更新跨市场ETF台账补票信息
     *
     * @param vo
     * @return
     */
    public List<AccountVo> renewFillEtfAccount(Account vo, ParamVo paramVo) throws Exception {
        log.info("更新" + vo.getPurchaseDate() + "深圳跨市场ETF台账补票数据开始");
        List<AccountVo> voList = new ArrayList<>();
        for (String maket : this.getMarketList()) {
            //获取自己市场对应的参数信息
            ParamVo etfParamVo = paramService.getEtfParamVo(maket, paramVo);
            vo.setMarket(maket);
            List<Account> list = accountService.queryEtfAccountFill(vo, etfParamVo);
            if (CollectionUtils.isEmpty(list)) {
                continue;
            }
            vo.setDealSeat(etfParamVo.getEtfFillSeat());
            //获取股票明细交易数据
            StockDealDetailed stockDealDetailed = new StockDealDetailed();
            stockDealDetailed.setMarket(vo.getMarket());
            stockDealDetailed.setAccountId(vo.getAccountId());
            stockDealDetailed.setFdate(DateUtil.strToLocalDate(vo.getPurchaseDate()));
            stockDealDetailed.setDealSeat(vo.getDealSeat());
            AccountVo accountVo = new AccountVo();
            accountVo.setMapFillDetail(feignValuationService.queryStockDealDetailed(stockDealDetailed));
            accountVo.setParamVo(etfParamVo);
            accountVo.setList(list);
            voList.add(accountVo);
        }
        log.info("更新" + vo.getPurchaseDate() + "深圳跨市场ETF台账补票数据结束");
        return voList;
    }

    /**
     * 计算替代金额
     *
     * @param vo
     * @param paramVo
     * @return
     * @throws Exception
     */
    private BigDecimal handleInitReplaceMoney(Account vo, ParamVo paramVo, String yesterday) throws Exception {
        if (YssMarketEnum.S.getCode().equals(vo.getMarket())) { //不是先到先补的模式
            return vo.getDealMoney();
        }
        Quotation quotation = accountService.queryQuotation(yesterday, vo.getSecurityCode());
        if (null == quotation) {
            return BigDecimal.ZERO;
        }
        //昨日行情
        BigDecimal organizationPrice = (1 == paramVo.getEtfOrganizationPrice()) ? quotation.getQuotationClosingPrice()
                : quotation.getQuotationAveragePrice();
        if (EtfManageEnum.ETF_PURCHASE.getCode().equals(vo.getBusinessType())) {
            if (BigDecimalUtil.compareTo(vo.getPurchaseReplaceMoney(), BigDecimal.ZERO) == 0) {
                //申购的替代金额 replaceMoney  dealAmount*(1+溢折价比例)*申赎日期的收盘价
                return BigDecimalUtil.multiply(BigDecimalUtil.multiply(vo.getAmount(), BigDecimalUtil.add(BigDecimal.ONE, new BigDecimal(vo.getPremiumScale())))
                        , organizationPrice, Integer.valueOf(EtfManageEnum.ETF_MONEY_SCALE.getCode()));
            }
            return BigDecimalUtil.divide(BigDecimalUtil.multiply(vo.getPurchaseReplaceMoney(), vo.getOneLevelSecurityCodeAmount()), paramVo.getEtfBenchmarkScale(), 2);
        }
        if (vo.getRedeemReplaceMoney().compareTo(BigDecimal.ZERO) == 0 && new BigDecimal(vo.getDiscountScale()).compareTo(BigDecimal.ZERO) != 0) {
            // 赎回的替代金额 dealAmount*(1-折折价比例)*申赎日期的收盘价
            return BigDecimalUtil.multiply(BigDecimalUtil.multiply(vo.getAmount(), BigDecimalUtil.subtract(BigDecimal.ONE, new BigDecimal(vo.getDiscountScale())))
                    , organizationPrice, Integer.valueOf(EtfManageEnum.ETF_MONEY_SCALE.getCode()));
        }
        if (vo.getRedeemReplaceMoney().compareTo(BigDecimal.ZERO) == 0 && new BigDecimal(vo.getDiscountScale()).compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimalUtil.multiply(organizationPrice, BigDecimalUtil.multiply(vo.getAmount(),
                    BigDecimalUtil.subtract(BigDecimal.ONE, new BigDecimal(vo.getPremiumScale()))), Integer.valueOf(EtfManageEnum.ETF_MONEY_SCALE.getCode()));
        }
        return BigDecimalUtil.divide(BigDecimalUtil.multiply(vo.getRedeemReplaceMoney(), vo.getOneLevelSecurityCodeAmount()), paramVo.getEtfBenchmarkScale(), 2);
    }

    /**
     * 股票类ETF 获取申购和数据的汇总替代金额
     *
     * @param vo
     * @param paramVo
     * @return
     * @throws Exception
     */
    private Map<String, BigDecimal> querySumReplaceMoney(Account vo, ParamVo paramVo) throws Exception {
        Map<String, BigDecimal> map = new HashMap<>();
        try {
            map.put(EtfManageEnum.ETF_PURCHASE.getCode(), BigDecimal.ZERO);
            map.put(EtfManageEnum.ETF_REDEMPTION.getCode(), BigDecimal.ZERO);
            List<DealDetaild> dealDetaildList = dealDetaildService.querySumReplaceMoneyAndAmount(vo.getPurchaseDate(), paramVo);
            //查询篮子里必须现金替代的替代金额
            QueryWrapper<Skep> wrapperEtfSkep = new QueryWrapper<>();
            wrapperEtfSkep.select("SUM(PURCHASE_REPLACE_MONEY) as purchaseReplaceMoney", "SUM(PURCHASE_REPLACE_MONEY) as redeemReplaceMoney");
            wrapperEtfSkep.eq("ACCOUNT_ID", vo.getAccountId());
            wrapperEtfSkep.in("REPLACE_CODE", Arrays.asList(EtfReplaceCodeEnum.H_REPLACE_CODE_TWO.getCode(),
                    EtfReplaceCodeEnum.H_REPLACE_CODE_FOUR.getCode()));
            wrapperEtfSkep.eq("ETF_MARKET", paramVo.getEtfMarket());
            wrapperEtfSkep.eq("ETF_MODE", paramVo.getEtfMode());
            wrapperEtfSkep.eq("ETF_TYPE", vo.getEtfType());
            wrapperEtfSkep.eq("FDATE", vo.getPurchaseDate());
            Skep gpSkepSumReplaceMoney = skepService.getOne(wrapperEtfSkep);
            if (null == gpSkepSumReplaceMoney) {
                return map;
            }
            //分别计算申购和赎回篮子数
            for (DealDetaild dealDetaild : dealDetaildList) {
                if (null == dealDetaild) {
                    continue;
                }
                BigDecimal etfSkepAmount = dealDetaild.getDealAmount().divide(paramVo.getEtfBenchmarkScale());
                if (EtfManageEnum.ETF_PURCHASE.getCode().equals(dealDetaild.getBusinessType())) {
                    map.put(dealDetaild.getBusinessType(), dealDetaild.getDealMoney().subtract(gpSkepSumReplaceMoney.getPurchaseReplaceMoney().multiply(etfSkepAmount)));
                    continue;
                } else if (EtfManageEnum.ETF_REDEMPTION.getCode().equals(dealDetaild.getBusinessType())) {
                    map.put(dealDetaild.getBusinessType(), dealDetaild.getDealMoney().subtract(gpSkepSumReplaceMoney.getRedeemReplaceMoney().multiply(etfSkepAmount)));
                    continue;
                }
            }
        } catch (Exception ex) {
            log.error("计算交易文件中申购和赎回汇总额替代金额出错：" + ex.toString());
            throw new BusinessException("计算交易文件中申购和赎回汇总额替代金额出错,请稍后重试！");
        }
        return map;
    }
}
